<?php
/**
 * Class for handle all information aboult price caculation.
 *
 * @access 	public
 * @author 	Salvatore Borrelli
 * @copyright	ResMania 2011 all rights reserved.
 * @version	1.0
 * @link	http://developer.resmania.com/api
 * @since  	11-2011
 */
class RM_PriceBands_Calculator {
    /**
     * @var RM_UnitPriceBands
     */
    protected $unitPricesModel;
    /**
     * @var RM_PriceBands
     */
    protected $pricesModel;
    /**
     * Configuration settings
     */
    protected $settings = array();
    /**
     * @var Zend_Translate
     */
    protected $translate;

    /**
     * Creates a new instance
     * @param RM_UnitPriceBands $unitPricesModel the price bands model for single units
     * @param RM_PriceBands $pricesModel the general price bands model
     * @param array $setting the price bands configuration settings
     * @param Zend_Translate $translate the language translator
     */
    public function  __construct($unitPricesModel, $pricesModel, $settings, $translate) {
        $this->setUnitPricesModel($unitPricesModel);
        $this->setPricesModel($pricesModel);
        $this->setSettings($settings);
        $this->setTranslate($translate);
    }
    /**
     * Gets the unit prices model
     * @return the unit prices model
     */
    protected function getUnitPricesModel() {
        return $this->unitPricesModel;
    }
    /**
     * Sets the unit prices model
     * @param unitPricesModel the unit prices model
     */
    protected function setUnitPricesModel($unitPricesModel) {
        $this->unitPricesModel = $unitPricesModel;
    }
    /**
     * Gets the prices model
     * @return the prices model
     */
    protected function getPricesModel() {
        return $this->pricesModel;
    }
    /**
     * Sets the prices model
     * @param pricesModel the pricesmodel
     */
    protected function setPricesModel($pricesModel) {
        $this->pricesModel = $pricesModel;
    }
    /**
     * Gets the configuration settings
     * @return the configuration settings
     */
    protected function getSettings() {
        return $this->settings;
    }
    /**
     * Sets the configuration settings
     * @param settings configuration settings
     */
    protected function setSettings($settings) {
        $this->settings = $settings;
    }
    /**
     * Return the value of a given configuration parameter
     * @param name the paramente name
     * @return the configuration value, or <code>null</code> if not found
     */
    protected function getSetting($name) {
        $value = null;
        $settings = $this->getSettings();
        foreach($settings as $setting) {
            if (!strcmp($setting['name'], $name)) {
                // found
                if (array_key_exists('unit_value', $setting)) {
                    // gets the unit value
                    $value = $setting['unit_value'];
                }
                else {
                    // gets the default value
                    $value = $setting['default_value'];
                }
                break;
            }
        }
        return $value;
    }
    /**
     * Gets the language translator
     * @return the language translator
     */
    protected function getTranslate() {
        return $this->translate;
    }
    /**
     * Sets the language translator
     * @param translate language translator
     */
    protected function setTranslate($translate) {
        $this->translate = $translate;
    }
    /**
     * Calculate the price for a given number of days and band configuration scheme
     * @param [int] the unit identifier
     * @param [int] days the number of days
     * @param [array] scheme the band configuration scheme
     * @return [float] the calculated price
     */
    protected function getPrice($unitId, $days, $scheme) {
        $price = 0;
        // loads a suitable bands configuration for this number of days
        $pricesModel = $this->getPricesModel();
        $bandId = $pricesModel->findContaining($days);
        if ($bandId>-1) {
            // gets this band's price from the scheme
            if (array_key_exists("band_$bandId", $scheme)) {
                $price = floatval($scheme["band_$bandId"])*$days;
            }
        }
        return $price;
    }
    /**
     * Applies the rounding settings to a given reservation length
     * @param len the reservation length
     * @return the rounded reservation length
     */
    protected function roundReservation($len) {
        $roundedLen = $len;
        $rdn = $this->getSetting('round_down_time');
        $rup = $this->getSetting('round_up_time');
        if ($rup==1 && $rdn==1) {
            $roundedLen = round($len);
        }
        else if ($rdn==1) {
            $roundedLen = intval($len);
        }
        else if ($rup==1) {
            $roundedLen = intval($len)+1;
        }
        return $roundedLen;
    }
    /**
     * Calculate total price for one unit
     * @param RM_Prices_Information $information
     * @return the total price
     */
    public function getTotalUnitPrice($information) {
        $unitPrice = 0;
        $unit = $information->getUnit();
        $period = $information->getPeriod();
        $persons = $information->getPersons();
        $pstart = $period->getStart();
        $pend = $period->getEnd();
        // gets the price bands for this unit
        $unitId = $unit->id;
        $pricesModel = $this->getUnitPricesModel();
        $prices = $pricesModel->getExpandedUnitPrices($unitId, 'start_datetime');
        $periodsCount = count($prices);
        $curPeriod = null;
        foreach($prices as $idx=>$price) {
            // check if there is an intersection with the current period
            $dtStart = new RM_Date(strtotime($price['start_datetime']));
            $dtStart->set($pstart->get('H'), 'H');
            $dtStart->set($pstart->get('i'), 'i');
            $dtEnd = new RM_Date(strtotime($price['end_datetime']));
            $dtEnd->set($pend->get('H'), 'H');
            $dtEnd->set($pend->get('i'), 'i');
            $curPeriod = new RM_Reservation_Period($dtStart, $dtEnd);
            $pint = $curPeriod->getIntersection($period);
            $daysCount = 0;
            if (!empty($pint)) {
                $daysCount = $this->roundReservation(floatval($pint->getLength(false))/24.0);
                if ($dtEnd->isEarlier($pend)) {
                    // includes the last day of this period
                    $daysCount++;
                }
            }
            else if ((0==$pstart->compareDate($dtEnd)) && $dtEnd->isEarlier($pend)) {
                // reservation start on last day of this period
                $daysCount = 1;
            }
            if ($daysCount>0) {
                // compute prices for this days count
                $periodPrice = $this->getPrice($unitId, $daysCount, $price);
                $unitPrice += $periodPrice;
            }
        }

        // todo: config pricing per person pricing if on run following...
        $config = new RM_PriceBandsConfig();
        $priceBy = $config->fetchValueByUnit($unitId, 'price_by');

        if ($priceBy !== "unit"){
            $totalPeople = $persons->getAdults() + $persons->getChildren() + $persons->getInfants();
            if ( $totalPeople >0 ) {
                $unitPrice *= $totalPeople;
            }
        }
        return RM_Environment::getInstance()->roundPrice($unitPrice);
    }
}